﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using EnvDTE;
using System.IO;

using Microsoft.JScript.Compiler;
using Microsoft.JScript.Compiler.ParseTree;
using EnvDTE80;
using System.Resources;
using System.Reflection;
using System.Diagnostics;
using System.Threading;
using System.Globalization;

namespace Yuyi.PluginForJS.Addin
{
    public partial class NavigationTreeView : UserControl
    {
        private MyResourceManager resourceManager;

        private DTE m_dte = null;
        public DTE DTE
        {
            set { m_dte = value; }
        }
        
        public NavigationTreeView()
        {
            InitializeComponent();

            resourceManager = MyResourceManager.Current();
            LoadIcon();
        }
        private void mainTabControl_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            if (mainTabControl.SelectedIndex == 0)
            {
                btnRefresh.Enabled = true;
                btnCompression.Enabled = false;
            }
            else if (mainTabControl.SelectedIndex == 1)
            {
                btnRefresh.Enabled = false;
                btnCompression.Enabled = true;
                InitialFileChangedList();
            }
        }
        private void treeViewFiles_NodeMouseDoubleClick(object sender, System.Windows.Forms.TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (e.Node != null && e.Node.Tag != null && e.Node.Tag.ToString() != "root")
                {
                    try
                    {
                        Window currentFile = m_dte.OpenFile(EnvDTE.Constants.vsViewKindTextView, e.Node.Tag.ToString());
                        if (!currentFile.Visible)
                            currentFile.Visible = true;
                    }
                    catch { }
                }
            }
        }
        private IList<string> hidenFiles;
        private void InitialFileChangedList()
        {
            if (m_dte.Solution == null || m_dte.Solution.Projects == null || m_dte.Solution.Projects.Count <= 0) return;
            treeViewFiles.Nodes.Clear();
            TreeNode solutionNode = new TreeNode();
            solutionNode.Text = m_dte.Solution.FullName;
            solutionNode.Tag = "root";
            treeViewFiles.Nodes.Add(solutionNode);
            hidenFiles = new List<string>();
            foreach (Project p in m_dte.Solution.Projects)
            {
                if (p.ProjectItems != null)
                {
                    InitialFileChangedList(p.ProjectItems);
                }
            }
            solutionNode.Expand();
        }
        private void InitialFileChangedList(ProjectItems projectItems)
        {
            foreach (ProjectItem pi in projectItems)
            {
                if (pi.ProjectItems == null)
                {
                    string itemFullName = pi.get_FileNames(1);
                    if (itemFullName.EndsWith("js"))
                    {
                        if (itemFullName.EndsWith("compression.js"))
                        {
                            hidenFiles.Add(itemFullName);
                            continue;
                        }
                        TreeNode node = new TreeNode(pi.Name);
                        node.Tag = itemFullName;
                        treeViewFiles.Nodes[0].Nodes.Add(node);
                    }
                    continue;
                }

                if (pi.ProjectItems.Count > 0)
                {
                    InitialFileChangedList(pi.ProjectItems);
                }
                else
                {
                    string itemFullName = pi.get_FileNames(1);
                    if (itemFullName.EndsWith("js"))
                    {
                        if (itemFullName.EndsWith("compression.js"))
                        {
                            hidenFiles.Add(itemFullName);
                            continue;
                        }
                        TreeNode node = new TreeNode(pi.Name);
                        node.Tag = itemFullName;
                        treeViewFiles.Nodes[0].Nodes.Add(node);
                    }
                }
            }
            if (hidenFiles == null || hidenFiles.Count <= 0) return;
            foreach(string fileName in hidenFiles)
            {
                foreach (TreeNode node in treeViewFiles.Nodes[0].Nodes)
                { 
                    string name = fileName.Substring(0,fileName.LastIndexOf('.'));
                    name = name.Substring(0,name.LastIndexOf('.'))+".js";
                    if (name == node.Text)
                    {
                        TreeNode child = new TreeNode(fileName);
                        child.Tag = new FileInfo(node.Tag.ToString()).DirectoryName + "\\" + fileName;
                        node.Nodes.Add(child);
                    }
                }
            }

        }

        

        public void Init(DTE dte,Document doc)
        {
            this.m_dte = dte;
            this._doc = doc;
            LoadLanguage();
            _code = new CodeService(m_dte, Doc).LoadCode();
        }
        /// <summary>
        /// 从资源文件加载图标
        /// </summary>
        private void LoadIcon()
        {
            Image functionImage = resourceManager.GetImage("function");
            Image fileImage = resourceManager.GetImage("file");
            Image functionClickedImage = resourceManager.GetImage("function_");
            ImageList imageList = new ImageList();
            imageList.Images.Add("function", functionImage);
            imageList.Images.Add("file", fileImage);
            imageList.Images.Add("function_", functionClickedImage);
            treeViewMembers.ImageList = imageList;
        }

        private Document _doc;

        private Document Doc
        {
            get
            {
                if (_doc == null)
                    return m_dte.ActiveDocument;
                return _doc;
            }
        }

        public TextSelection Selection
        {
            get
            {
                return (TextSelection)Doc.Selection;
            }
        }
        private string _code;
        public string Code
        {
            get { return _code; }
        }

        public int EndOfFile
        {
            get
            {
                TextDocument textDoc = (TextDocument)Doc.Object("TextDocument");
                if (textDoc != null)
                    return textDoc.EndPoint.Line;
                return 0;
            }
        }


        public void LoadFunctionList()
        {
            if (Doc == null || Doc.Language != "HTML") return;
            FunctionList functionList = new FunctionList(Code);
            IList<AbstractNode> nodes = functionList.LoadFunctionList();

            TreeNode root = new TreeNode(Doc.Name);
            root.Tag = "root";
            root.ImageKey = "file";
            root.SelectedImageKey = "file";

            AppendNode(nodes, root);
            treeViewMembers.Nodes.Clear();
            treeViewMembers.Nodes.Add(root);
            root.Expand();
        }

        private void AppendNode(IList<AbstractNode> nodes, TreeNode pTreeNode)
        {
            if (nodes == null || nodes.Count <= 0) return;
            foreach (AbstractNode node in nodes)
            { 
                TreeNode tNode = new TreeNode(node.ToString());
                tNode.ImageKey = node.ImageKey;
                tNode.SelectedImageKey = node.ImageKey + "_";
                tNode.Tag = node;
                pTreeNode.Nodes.Add(tNode);
                AppendNode(node.ChildNodes, tNode);
            }
        }

        private void treeViewMembers_AfterSelect(object sender, TreeViewEventArgs e)
        {

            if (e.Node.Tag.ToString() == "root") return;
            if (Doc == null || Doc.Language != "HTML") return;
           
            AbstractNode node = e.Node.Tag as AbstractNode;
            if (node != null)
            {
                int line = node.StartLine;
                Selection.GotoLine(line, true);
            }
        }

        public void Clear()
        {
            this.treeViewMembers.Nodes.Clear();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            try
            {
                _code = new CodeService(m_dte, Doc).LoadCode();
                new OutlineService(m_dte, Doc).Outline();
                LoadFunctionList();

            }
            catch { }
        }

        private void btnCompression_Click(object sender, EventArgs e)
        {
            TreeNode selectedNode = treeViewFiles.SelectedNode;
            if (selectedNode == null || selectedNode.Tag.ToString() == "root") return;

            string folderRoot = new FileInfo(selectedNode.Tag.ToString()).DirectoryName;
            string cshPath = string.Format(@"{0}\csh.cmd", folderRoot);
            string whsPath = string.Format(@"{0}\ESC.wsf", folderRoot);

            string inFileName = selectedNode.Text;
            string outputFileName = string.Format("{0}.compression.js", inFileName.Substring(0, inFileName.LastIndexOf('.')));

            CreateFileIfNeeded(cshPath);
            CreateFileIfNeeded(whsPath);

            System.Diagnostics.Process process = new System.Diagnostics.Process();
            ProcessStartInfo psi = new ProcessStartInfo("cscript", string.Format("esc.wsf -l 3 -ow {0} {1}",outputFileName,inFileName));
            psi.WorkingDirectory = folderRoot;
            process.StartInfo = psi;
            process.EnableRaisingEvents = false;
            psi.UseShellExecute = false;
            psi.RedirectStandardError = true;
            psi.RedirectStandardOutput = true;
            psi.CreateNoWindow = true;
            try
            {
                process.Start();
                bool finished = process.WaitForExit(10 * 1000);
                if (!finished)
                {
                    process.Kill();
                    return;
                }
                selectedNode.Nodes.Clear();
                TreeNode node = new TreeNode(outputFileName);
                node.Tag = string.Format("{0}\\{1}", folderRoot, outputFileName);
                selectedNode.Nodes.Add(node);
            }
            catch { }
            finally
            {
                process.Close();
            }
        }

        private static void CreateFileIfNeeded(string filePath)
        {
            if (!File.Exists(filePath))
            {
                string fileName = new FileInfo(filePath).Name;
                string ns = typeof(NavigationTreeView).Namespace;

                using (StreamReader sr = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(string.Format("{0}.Resources.{1}", ns, fileName))))
                {
                    File.WriteAllText(filePath, sr.ReadToEnd());
                }
            }
        }

        private void LoadLanguage()
        { 
            CultureInfo cultureInfo = new CultureInfo(m_dte.LocaleID);
            this.btnRefresh.Text = resourceManager.GetString(MyResourceManager.strRefresh, cultureInfo);
            this.btnCompression.Text = resourceManager.GetString(MyResourceManager.strCompression, cultureInfo);
            this.tabPageOutline.Text = resourceManager.GetString(MyResourceManager.strOutline, cultureInfo);
            this.tabPageFile.Text = resourceManager.GetString(MyResourceManager.strFile, cultureInfo);
        }
    }
}
